﻿using System;
using System.Linq;
using System.Reactive.Linq;
using System.Windows;
using System.Windows.Interactivity;
using CardPlay.Client.Model;
using CardPlay.Client.Tools;

namespace CardPlay.Client.Behaviors
{
    public class PlayerBehavior : Behavior<FrameworkElement>, IToolSite
    {
        private readonly ITool[] _tools;
        private IDisposable _subscription;

        public PlayerBehavior()
        {
            _tools = new ITool[]
            {
                new InvokeActionTool(this),
                new DragPileTool(this),
                new PeekTool(this) 
            };
        }

        public object GetService(Type serviceType)
        {
            return ((ITreeNode) AssociatedObject.DataContext).GetService(serviceType);
        }

        public ITool ActiveTool
        {
            get; set;
        }

        protected override void OnAttached()
        {
            base.OnAttached();

            var hookedEvents = new[]
            {
                InputEvent.MouseMove,
                InputEvent.MouseEnter,
                InputEvent.MouseLeave,
                InputEvent.MouseLeftButtonUp,
                InputEvent.MouseLeftButtonDown,
                InputEvent.MouseRightButtonUp,
                InputEvent.MouseRightButtonDown,
                InputEvent.KeyDown,
                InputEvent.KeyUp,
                InputEvent.LostMouseCapture
            };

            _subscription = hookedEvents
                .Select(name =>
                    Observable
                        .FromEventPattern<RoutedEventArgs>(AssociatedObject, name)
                        .Select(eventPattern => new InputEvent(AssociatedObject, name, eventPattern.EventArgs)))
                .Merge()
                .SubscribeOnDispatcher()
                .Subscribe(ProcessEvent);
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            if (_subscription != null) _subscription.Dispose();
        }

        private void ProcessEvent(InputEvent inputEvent)
        {
            //Debug.WriteLine(inputEvent);

            if (ActiveTool != null)
            {
                ActiveTool.Process(inputEvent);
            }
            else
            {
                foreach (var tool in _tools)
                {
                    tool.Process(inputEvent);
                    if (ActiveTool != null) break;
                }
            }
        }
    }
}